<template>
    <view class="uni-numbox">
        <view class="uni-numbox__minus uni-numbox-btns" :style="{ background }" @click="_calcValue('minus')">
            <text
                class="uni-numbox--text"
                :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }"
                :style="{ color }"
                >-</text
            >
        </view>
        <input
            v-model="inputValue"
            :disabled="disabled"
            class="uni-numbox__value"
            :type="step < 1 ? 'digit' : 'number'"
            :style="{ background, color, width: widthWithPx }"
            @focus="_onFocus"
            @blur="_onBlur"
        />
        <view class="uni-numbox__plus uni-numbox-btns" :style="{ background }" @click="_calcValue('plus')">
            <text
                class="uni-numbox--text"
                :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }"
                :style="{ color }"
                >+</text
            >
        </view>
    </view>
</template>
<script>
/**
 * NumberBox 数字输入框
 * @description 带加减按钮的数字输入框
 * @tutorial https://ext.dcloud.net.cn/plugin?id=31
 * @property {Number} value 输入框当前值
 * @property {Number} min 最小值
 * @property {Number} max 最大值
 * @property {Number} step 每次点击改变的间隔大小
 * @property {String} background 背景色
 * @property {String} color 字体颜色（前景色）
 * @property {Number} width 输入框宽度(单位:px)
 * @property {Boolean} disabled = [true|false] 是否为禁用状态
 * @event {Function} change 输入框值改变时触发的事件，参数为输入框当前的 value
 * @event {Function} focus 输入框聚焦时触发的事件，参数为 event 对象
 * @event {Function} blur 输入框失焦时触发的事件，参数为 event 对象
 */

export default {
    name: "UniNumberBox",
    props: {
        value: {
            type: [Number, String],
            default: 1
        },
        modelValue: {
            type: [Number, String],
            default: 1
        },
        min: {
            type: Number,
            default: 0
        },
        max: {
            type: Number,
            default: 100
        },
        step: {
            type: Number,
            default: 1
        },
        background: {
            type: String,
            default: "#f5f5f5"
        },
        color: {
            type: String,
            default: "#333"
        },
        disabled: {
            type: Boolean,
            default: false
        },
        width: {
            type: Number,
            default: 40
        }
    },
    emits: ["change", "input", "update:modelValue", "blur", "focus"],
    data() {
        return {
            inputValue: 0
        };
    },
    computed: {
        widthWithPx() {
            return this.width + "px";
        }
    },
    watch: {
        value(val) {
            this.inputValue = +val;
        },
        modelValue(val) {
            this.inputValue = +val;
        }
    },
    created() {
        if (this.value === 1) {
            this.inputValue = +this.modelValue;
        }
        if (this.modelValue === 1) {
            this.inputValue = +this.value;
        }
    },
    methods: {
        _calcValue(type) {
            if (this.disabled) {
                return;
            }
            const scale = this._getDecimalScale();
            let value = this.inputValue * scale;
            let step = this.step * scale;
            if (type === "minus") {
                value -= step;
                if (value < this.min * scale) {
                    return;
                }
                if (value > this.max * scale) {
                    value = this.max * scale;
                }
            }

            if (type === "plus") {
                value += step;
                if (value > this.max * scale) {
                    return;
                }
                if (value < this.min * scale) {
                    value = this.min * scale;
                }
            }

            this.inputValue = (value / scale).toFixed(String(scale).length - 1);
            // TODO vue2 兼容
            this.$emit("input", +this.inputValue);
            // TODO vue3 兼容
            this.$emit("update:modelValue", +this.inputValue);
            this.$emit("change", +this.inputValue);
        },
        _getDecimalScale() {
            let scale = 1;
            // 浮点型
            if (~~this.step !== this.step) {
                scale = Math.pow(10, String(this.step).split(".")[1].length);
            }
            return scale;
        },
        _onBlur(event) {
            this.$emit("blur", event);
            let value = event.detail.value;
            if (isNaN(value)) {
                this.inputValue = this.value;
                return;
            }
            value = +value;
            if (value > this.max) {
                value = this.max;
            } else if (value < this.min) {
                value = this.min;
            }
            const scale = this._getDecimalScale();
            this.inputValue = value.toFixed(String(scale).length - 1);
            this.$emit("input", +this.inputValue);
            this.$emit("update:modelValue", +this.inputValue);
            this.$emit("change", +this.inputValue);
        },
        _onFocus(event) {
            this.$emit("focus", event);
        }
    }
};
</script>
<style lang="scss">
$box-height: 26px;
$bg: #f5f5f5;
$br: 2px;
$color: #333;

.uni-numbox {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
}

.uni-numbox-btns {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: row;
    align-items: center;
    justify-content: center;
    padding: 0 8px;
    background-color: $bg;
    /* #ifdef H5 */
    cursor: pointer;
    /* #endif */
}

.uni-numbox__value {
    margin: 0 2px;
    background-color: $bg;
    width: 40px;
    height: $box-height;
    text-align: center;
    font-size: 14px;
    border-width: 0;
    color: $color;
}

.uni-numbox__minus {
    border-top-left-radius: $br;
    border-bottom-left-radius: $br;
}

.uni-numbox__plus {
    border-top-right-radius: $br;
    border-bottom-right-radius: $br;
}

.uni-numbox--text {
    // fix nvue
    line-height: 20px;
    margin-bottom: 2px;
    font-size: 20px;
    font-weight: 300;
    color: $color;
}

.uni-numbox .uni-numbox--disabled {
    color: #c0c0c0 !important;
    /* #ifdef H5 */
    cursor: not-allowed;
    /* #endif */
}
</style>
